#ifndef FABRIC_H
#define FABRIC_H

#include <QtOpenGL>
#include <QString>
#include <iostream>

#include <vector>
#include "color.h"
#include "vector3d.h"
#include "vector.h"
#include "spring.h"
#include "particle.h"
#include "face.h"
#include "forwardEulerMethod.h"
#include "rungeKuttaMethod.h"
#include "matrix.h"
#include "state.h"

#define ERROR 0.00001

class Fabric
{
	public:
		Fabric(unsigned int = 0); //base constructor

		Fabric(unsigned int, std::vector<Particle *>, std::vector<Spring *>, std::vector<Face *>, bool = false);

		Fabric(unsigned int, std::vector<Particle *>, std::vector<Spring *>, std::vector<Face *>, unsigned int, const Matrix &, bool = false); //constructor for the file
        //Fabric(double, double);
		~Fabric();

		unsigned int getID() const {return id;};

		bool isSelected() const {return selected;};

		void select(bool _b) {selected = _b;};

		double getDensity() const {return ho;};

		void setDensity(double _ho) {ho = _ho; recalculateParticlesMasses();};

		double getThickness() const {return thickness;};

		void setThickness(double _thickness) {thickness = _thickness; recalculateParticlesMasses();};

		void setDensityAndThickness(double _ho, double _thickness) {ho = _ho; thickness = _thickness; recalculateParticlesMasses();};

		void recalculateParticlesKd(double = 0.3);
		void recalculateParticlesMasses();
		void resetSpringsConstants(double = 2200, double = 2, double = 50, double = 1, double = 2, double = 0.0005);

        const State &getState(); //return the current State

        void setState(const State &);//change the current state

        void updateState();

		virtual void draw(bool, bool, bool);

		void drawWireframe(); //draw wireframe

		void drawFill(bool, bool); //draw fill

		void addParticle(Particle *); //adds particles

		Particle *getParticle(int) const; //return the particle in the position i

		const std::vector<Particle *> &getParticles() const; //return the array of particles

		unsigned int getParticlesSize() const; //return the size of vector of particle

		void addSpring(Spring *); //add spring

		Spring *getSpring(int) const; //return spring in the position i

		const std::vector<Spring*> &getSprings() const; //return the array of springs

		unsigned int getSpringsSize() const; //return the size of vector of springs

		void updateSpringsLength(); // populate the vector position

		const State &restart();

		QString getSpringsFaces();

		QString getUV();

		QString getInitialState();

		void setParticleState(unsigned int, bool, bool, bool, const Vector3D &, const Vector3D &);

		bool hasTextureCoord() const {return hasTexture;};
		void setHasTexture(bool _b) {hasTexture = _b;};

    protected:
        unsigned int id;
        bool selected;
		bool hasTexture;

        double ho; //kg/m^3 - density
        double thickness; //m

        State currentState, initialState;

        //necessareamente o ID de cada um desses objetos é a posição em que ele se encontra na lista!
		std::vector<Particle *> particles;

		std::vector<Spring *> springs;

		std::vector<Face *> faces;

		Vector populatePosition();
};

#endif
